﻿using System;
using System.Collections.Generic;
using System.Globalization;

namespace ScrumPilot.Helpers
{
    public static class Helper
    {
        public static T GetValue<T>(string value)
        {
            T tRet = default(T);
            if (!String.IsNullOrWhiteSpace(value))
            {
                /*   if (typeof(T).FullName == "System.Boolean")
                    value = value.ToLower() == "yes" ? "True" : "False";*/
                var types = new[] { typeof(string), typeof(T).MakeByRefType() };
                var method = typeof(T).GetMethod("TryParse", types);
                if (method != null)
                {
                    var methodParams = new object[] { value, tRet };
                    method.Invoke(value, methodParams);
                    tRet = (T)methodParams[1];
                }
            }
            return tRet;
        }
    }

    #region date & time
    public static class DateTimeHelpers
    {

        /// <summary>
        /// Return first Date of Week 
        /// </summary>
        /// <param name="dt">Date in week</param>
        /// <param name="info">Culture</param>
        /// <returns>Date of first day in week (UTC)</returns>
        public static DateTime FirstDateOfWeek(this DateTime dt, CultureInfo info)
        {
            DayOfWeek firstday = info.DateTimeFormat.FirstDayOfWeek;
            DayOfWeek today = info.Calendar.GetDayOfWeek(dt);
            int diff = today - firstday;
            dt = dt.AddDays(-diff);
            return (new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0, DateTimeKind.Utc));
        }

        /// <summary>
        /// Return last Date of Week 
        /// </summary>
        /// <param name="dt">Date in week</param>
        /// <param name="info">Culture</param>
        /// <returns>Date of last day in week (UTC)</returns>
        public static DateTime LastDateOfWeek(this DateTime dt, CultureInfo info)
        {
            DateTime f = FirstDateOfWeek(dt, info).AddDays(6);
            return (new DateTime(f.Year, f.Month, f.Day, 23, 59, 59, 999, DateTimeKind.Utc));
        }

        /// <summary>
        /// Return the first Day of a month
        /// </summary>
        /// <param name="dt">Date in month</param>
        /// <returns>first day in month (UTC)</returns>
        public static DateTime FirstDateOfMonth(this DateTime dt)
        {
            return (new DateTime(dt.Year, dt.Month, 1, 0, 0, 0, 0, DateTimeKind.Utc));
        }

        /// <summary>
        /// Return last day of a month
        /// </summary>
        /// <param name="dt">Date in month</param>
        /// <returns>Last day in month (UTC)</returns>
        public static DateTime LastDateOfMonth(this DateTime dt)
        {
            DateTime f = dt.Month < 12
                             ? new DateTime(dt.Year, dt.Month + 1, 1, 23, 59, 59, 999, DateTimeKind.Utc)
                             : new DateTime(dt.Year + 1, 1, 1, 23, 59, 59, 999, DateTimeKind.Utc);
            return (f.AddDays(-1));
        }

        /// <summary>
        /// The First date in Java/Javascript time
        /// </summary>
        public static DateTime FirstDateforJava = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

        /// <summary>
        /// Convert a Java/JavaScript/Json date in .NET datetime (UTC)
        /// </summary>
        /// <param name="timestamp">Value of "tick" time</param>
        /// <returns>UTC datetime of timestamp</returns>
        public static Nullable<DateTime> ConvertFromJavaTimestamp(double timestamp)
        {
            return FirstDateforJava.AddMilliseconds(timestamp);
        }

        /// <summary>
        /// Convert a Java/JavaScript/Json date in .NET datetime (UTC)
        /// </summary>
        /// <returns>UTC datetime of timestamp</returns>
        public static Nullable<DateTime> ConvertFromJavaTimestamp(string jsonDate)
        {
            double timestamp;
            if (!string.IsNullOrWhiteSpace(jsonDate) && jsonDate.Length >= 19)
                if (Double.TryParse(jsonDate.Substring(6, 13), out timestamp))
                    return ConvertFromJavaTimestamp(timestamp);
            return null;
        }

        public static DateTime ScrumPilotStartPeriod(int spPeriod, CultureInfo ci)
        {
            DateTime dStart;
            switch (spPeriod)
            {
                case 0: // Week
                    dStart = DateTime.UtcNow.FirstDateOfWeek(ci).AddDays(-1);
                    break;
                case 1: // two weeks
                    dStart = DateTime.UtcNow.FirstDateOfWeek(ci).AddDays(-1).FirstDateOfWeek(ci);
                    break;
                case 2: // Month
                    dStart = DateTime.UtcNow.FirstDateOfMonth();
                    break;
                default:
                    dStart = DateTime.UtcNow;
                    break;
            }
            return dStart;
        }

        public static DateTime Max(DateTime a, DateTime b)
        {
            return a > b ? a : b;
        }

        public static DateTime Max(DateTime a, Nullable<DateTime> b)
        {
            if (b == null)
                return a;
            return Max(a, b.Value);
        }


        public static bool IsWorkingDay(this DateTime date)
        {
            return date.DayOfWeek != DayOfWeek.Saturday
                && date.DayOfWeek != DayOfWeek.Sunday;
        }

        public static int GetWorkDays(DateTime dStart, DateTime dEnd)
        {
            dStart = dStart.Date;
            dEnd = dEnd.Date;
            int wd = (dEnd.Subtract(dStart).Days) + 1;
            for (var dS = dStart; dS <= dEnd; dS = dS.AddDays(1))
            {
                if (!dS.IsWorkingDay())
                {
                    wd--;
                }
            }
            return wd;
        }

        public static List<DateTime> GetDateWorkDays(DateTime dStart, DateTime dEnd)
        {
            dStart = dStart.Date;
            dEnd = dEnd.Date;
            var dtRet = new List<DateTime>();
            for (var dS = dStart; dS <= dEnd; dS = dS.AddDays(1))
            {
                if (dS.IsWorkingDay())
                {
                    dtRet.Add(dS);
                }
            }
            return dtRet;
        }

        public static List<DateTime> GetDateWorkDays(DateTime dEnd, int numberOfDays)
        {
            dEnd = dEnd.Date;
            var dtRet = new List<DateTime>(numberOfDays);
            for (int i = 0; i < numberOfDays; dEnd = dEnd.AddDays(-1))
            {
                if (dEnd.IsWorkingDay())
                {
                    dtRet.Insert(0,dEnd);
                    i++;
                }

            }
            return dtRet;
        }
    }
    #endregion

    public class KeyValue
    {
        public KeyValue(String id, String name)
        {
            value = id;
            key = name;
        }

        public KeyValue(int id, String name) : this(id.ToString(CultureInfo.InvariantCulture), name) { }

        public string value { get; set; }
        public string key { get; set; }
    }
}